package com.robusta.app.web.interceptor;

import com.robusta.app.auth.api.UserAuthentication;
import com.robusta.app.domain.user.UserContextHolder;
import com.robusta.app.web.auth.AuthenticationTokenStrategy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.NoSuchElementException;

/**
 * User session is identified by an auth token.
 * This interceptor uses cookie based auth token retrieval and
 * looks up the user session. If a session is not obtained, the
 * user is redirected to the login page to get authenticated.
 */
public class AuthenticationInterceptor extends HandlerInterceptorAdapter {
    private static final Logger LOGGER = LoggerFactory.getLogger(AuthenticationInterceptor.class);
    @Autowired
    protected UserAuthentication authentication;
    @Autowired
    protected AuthenticationTokenStrategy tokenStrategy;
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if(handlerIsAnnotatedToSkipAuthentication(handler)) {
            LOGGER.debug("Skipping authentication for authentication disabled controller methods on: %s", getControllerClass(handler));
            return true;
        }
        String authToken;
        try {
            authToken = tokenStrategy.extractAuthenticationToken(request);
        } catch (NoSuchElementException e) {
            LOGGER.debug("Unable to retrieve authentication token from request. User need to login. Redirecting");
            response.sendRedirect("login.html");
            return false;
        }
        UserContextHolder.setCurrentUser(authentication.lookupUserSessionByToken(authToken).loggedUser());
        return super.preHandle(request, response, handler);
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        UserContextHolder.clear();
        super.postHandle(request, response, handler, modelAndView);    //To change body of overridden methods use File | Settings | File Templates.
    }

    private Class getControllerClass(Object handler) {
        if(!HandlerMethod.class.isAssignableFrom(handler.getClass())) {
            throw new RuntimeException(String.format("This version of authentication interceptor works only " +
                    "with handler class: %s, but received: %s", HandlerMethod.class, handler.getClass()));
        }
        return ((HandlerMethod)handler).getBean().getClass();
    }

    private boolean handlerIsAnnotatedToSkipAuthentication(Object handler) {
        return getControllerClass(handler).isAnnotationPresent(AuthDisabled.class);
    }
}
